import Vue,{VNode,PropOptions,CreateElement} from 'vue';
import 'tippy.js/animations/perspective.css';
import Tippy from '../tippy';
import Icon from '../icon';
import {AppendTo,PlainObject,SizeObj} from '../../../../types';
import {QVirtualScroll} from 'quasar';
/**
 * 输入类型
 */
export type InputType='text'|'password';
/**
 * 输入框形状
 */
export type ShapeType='square'|'round'|'noBorder';
/**
 * 输入框
 * @author 唐国雄
 * @date 2021/6/4
 * 属性----------------------
 * v-model			当前值, string
 * :type			输入类型, InputType
 * :shape			外形, ShapeType
 * :placeholder		占位文本, string
 * :format			格式化(失焦时)
 * :disable			禁用, boolean
 * :readonly		只读, boolean
 * :clearable		可清空, boolean
 * :maxlength		最大输入长度, number
 * :auto-focus		自动聚焦, boolean
 * :autocomplete	自动完成, string
 * :options			选项, Array<PlainObject|string>
 * :option-label	显示属性, string
 * :append-to		下拉框绑定位置, AppendTo
 * 事件----------------------
 * @input
 * @focus
 * @blur
 * @click-option	点击选项, PlainObject | string
 * 插槽----------------------
 * #prepend		前缀插槽
 * #append		后缀插槽
 * #before		前缀插槽(外部)
 * #after		后缀(外部)
 */
export default Vue.extend({
	name:'Input',
	props:{
		//输入类型
		type:{
			type:String,
			default:'text',
			validator(v){
				return [
					'text',
					'password',
				].indexOf(v)!==-1;
			}
		} as PropOptions<InputType>,
		//外形
		shape:{
			type:String,
			default:'square',
			validator(v){
				return [
					'square',
					'round',
					'noBorder',
				].indexOf(v)!==-1;
			}
		} as PropOptions<ShapeType>,
		//当前值
		value:{
			type:String,
			required:true,
			default:'',
		},
		//占位文本
		placeholder:String,
		//格式化(失焦时)
		format:Function,
		//禁用
		disable:Boolean,
		//只读
		readonly:Boolean,
		//可清空
		clearable:Boolean,
		//最大输入长度
		maxlength:Number,
		//自动聚焦
		autoFocus:Boolean,
		//自动完成
		autocomplete:String,
		//选项
		options:{
			type:Array,
		} as PropOptions<Array<PlainObject|string>>,
		//显示属性
		optionLabel:{
			type:String,
			default:'label'
		},
		//下拉框绑定位置, 默认document.body
		appendTo:{
			type:[String,Element,Function],
			validator(v){
				if(typeof v==='string'){
					return v==='parent';
				}
				return true;
			}
		} as PropOptions<AppendTo>,
	},
	data(){
		return {
			//组件宽度
			clientWidth:0,
			//是否聚焦输入框
			focus:false,
			//是否掩盖密码
			maskPassword:true,
			scrollTarget:null,
		};
	},
	computed:{
		classes():string{
			const {prepend,append,before,after}=this.$scopedSlots;
			return 'lexmis-Input'+
				` lexmis--${this.shape}`+
				(this.focus?' lexmis--focus':'')+
				(prepend?' lexmis--prepend':'')+
				(append?' lexmis--append':'')+
				(before?' lexmis--before':'')+
				(after?' lexmis--after':'')+
				(this.disable?' lexmis--disable':'')+
				(this.readonly?' lexmis--readonly':'');
		},
		//是否是真正的password类型
		passwordMode():boolean{
			return this.type==='password'&&this.maskPassword;
		},
		//传给Tippy组件的属性
		tippyOptions():PlainObject{
			return {
				advanced:true,
				head:false,
				disable:!(this.options&&this.options.length),
				appendTo:this.appendTo,
				width:0,
				minWidth:this.clientWidth,
				'tippy-options':{
					arrow:false,
					placement:'bottom-start',
					duration:[300,300],
					animation:'perspective',
					offset:[0,5],
					theme:'lexmis-widget',
					hideOnClick:false,
					onClickOutside(instance:any){
						instance.hide();
					},
				}
			};
		},
	},
	mounted(){
		this.$nextTick(function(){
			if(this.autoFocus){
				(this.$refs.input as HTMLElement).focus({preventScroll:true});
			}
			this.$watch(function(){
				return this.options?this.options.length:0;
			},function(count){
				if(count>1&&this.focus){
					// @ts-ignore
					this.$refs.Tippy.show();
				}
			},{immediate:true});
		});
	},
	activated(){
		if(this.autoFocus){
			(this.$refs.input as HTMLElement).focus({preventScroll:true});
		}
	},
	methods:{
		$_lexmis_renderContent(h:CreateElement,{height}:SizeObj){
			const optionLabel=this.optionLabel;
			const contentItem=(option:PlainObject|string,index:number) => {
				return h('div',{
					staticClass:'lexmis_option',
					key:index,
					on:{
						click:() => {
							this.$emit('click-option',option);
							// @ts-ignore
							this.$refs.Tippy.hide();
						}
					}
				},typeof option==='string'?option:option[optionLabel]);
			};
			if(this.options.length>=100){
				return h(QVirtualScroll,{
					staticClass:'lms-Input_options',
					staticStyle:{
						minWidth:this.clientWidth+'px',
					},
					ref:'virtualScroll',
					props:{
						scrollTarget:this.scrollTarget,
						virtualScrollSliceSize:Math.ceil(height/30*2),
						virtualScrollItemSize:30,
						items:this.options,
					},
					scopedSlots:{
						default:({item,index}) => contentItem(item,index)
					}
				});
			}else{
				return h('div',{
					staticClass:'lms-Input_options',
					staticStyle:{
						minWidth:this.clientWidth+'px',
					}
				},this.options.map(contentItem));
			}
		},
	},
	render(h):VNode{
		const {prepend,append,before,after}=this.$scopedSlots;
		let inputSelf=h('div',{
			staticClass:'lexmis_self',
			ref:'self',
			on:{
				click:() => {
					(this.$refs.input as HTMLElement).focus({preventScroll:true});
				}
			}
		},[
			prepend
				?h('div',{
					staticClass:'lexmis_prepend'
				},prepend(undefined))
				:null,
			h('input',{
				ref:'input',
				attrs:{
					maxlength:this.maxlength,
					readonly:this.readonly,
					autocomplete:this.autocomplete,
				},
				domProps:{
					value:!this.focus&&this.format
						?this.format(this.value)
						:this.value,
					type:this.passwordMode?'password':'text',
					placeholder:this.placeholder,
					disabled:this.disable,
				},
				on:{
					input:(e:InputEvent) => {
						const inputVal=(e.target as HTMLInputElement).value;
						if(this.value!==inputVal){
							this.$emit('input',inputVal);
						}
					},
					focus:() => {
						this.focus=true;
						this.$emit('focus');
					},
					blur:() => {
						this.focus=false;
						this.$emit('blur');
					},
				}
			}),
			this.type==='password'&&this.value
				?h('div',{
					staticClass:'lexmis_append lexmis_inner'
				},[
					h(Icon,{
						props:{
							name:this.passwordMode?'visibility':'visibility_off'
						},
						on:{
							click:() => {
								this.maskPassword=!this.maskPassword;
							}
						}
					})
				])
				:this.clearable&&this.value&&!this.disable
					?h('div',{
						staticClass:'lexmis_append lexmis_inner'
					},[
						h(Icon,{
							props:{
								name:'cancel'
							},
							on:{
								click:() => {
									this.$emit('input','');
								}
							}
						})
					])
					:(
						append
							?h('div',{
								staticClass:'lexmis_append'
							},append(undefined))
							:null
					)
		]);
		if(this.options!==undefined){
			const oldInputSelf=inputSelf;
			inputSelf=h(Tippy,{
				ref:'Tippy',
				staticClass:'lms-Input_Tippy',
				props:this.tippyOptions,
				on:{
					show:() => {
						this.clientWidth=(this.$refs.self as HTMLElement).offsetWidth;
						this.$nextTick(function(){
							this.$nextTick(function(){
								// @ts-ignore
								this.scrollTarget=this.$refs.Tippy.$refs.scroll.getVScrollTarget();
							});
						});
					},
				},
				scopedSlots:{
					content:(props) => this.$_lexmis_renderContent(h,props),
					default:() => oldInputSelf,
				},
			});
		}
		return h('div',{
			staticClass:this.classes,
		},[
			before
				?h('div',{
					staticClass:'lexmis_before'
				},before(undefined))
				:null,
			inputSelf,
			after
				?h('div',{
					staticClass:'lexmis_after'
				},after(undefined))
				:null,
		]);
	},
});
